package com.bibrApp.difu.utils;

import android.annotation.SuppressLint;
import android.os.Build;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;

import org.json.JSONException;
import org.json.JSONObject;

import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;

import androidx.annotation.RequiresApi;

/**
 * @date 2019/9/18
 * DES 对称加密
 * RSA 非对称加密 先进行8位随机key进行非对称加密；再对时间和parma进行对称加密
 */
public class EncryptUtils {
    // 字符编码格式
    private static final String CHARSET = "UTF-8";
    // 定义jackson对象
    private static final ObjectMapper MAPPER = new ObjectMapper();

    private static String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDn/QnUfkKkQpG++6YDUYo8qc0mrcRbRsmokp3EJZJrwIblldv6W2+yAIWkkel4GzsL+oklZReqZcG4F+ug3otc6IZa3fFMXuaDzoDzicdOABe2s8igLjMcfhujI9MqYvkVVSyFWdVOLNAnzQJgkisnHKZGPQZcxnQAHxTOUco+LwIDAQAB";

    //非对称密钥算法
    public static final String KEY_ALGORITHM = "RSA/NONE/PKCS1Padding";

    /**
     * 将对象转换成json字符串。
     *
     * @param data
     * @return
     */
    public static String objectToJson(Object data) {
        if (data == null) {
            throw new RuntimeException("data is null!");
        }
        try {
            MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            String string = MAPPER.writeValueAsString(data);
            return string;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String stringToMap(String str) {
        if (str == null) {
            throw new RuntimeException("str is null!");
        }
        if (!TextUtils.isEmpty(str)) {
            Gson gson = new Gson();
            Map<String, String> map = new HashMap<>();
            map = gson.fromJson(str, map.getClass());
            String name = map.get("ciphertext");
            return name;
        }
        return "";
    }

    public static JSONObject stringToJson(String str) {
        if (str == null) {
            throw new RuntimeException("str is null!");
        }
        JSONObject jsonObject = null;
        if (!TextUtils.isEmpty(str)) {
            try {
                jsonObject = new JSONObject(str);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return jsonObject;
    }

    /**
     * @return
     * @Object parm 对参数进行加密
     */
    @SuppressLint({"NewApi", "LocalSuppress"})
    public static Map<String, String> encrypt(Object parm) {
        if (parm == null) {
            throw new RuntimeException("parm is null!");
        }
        Log.e("dj", "parm===" + parm);
        String jsonParm = objectToJson(parm);
        Log.e("dj", "jsonParm===" + jsonParm);
        String randomKey = getRandomString(8);
        //对公钥进行RSA非对称加密
        String encryptRSA = null;
        try {
            encryptRSA = encryptRSA(randomKey, PUBLIC_KEY);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //对时间和参数进行DES对称加密
        long time = System.currentTimeMillis();
        String timeDES = encode(randomKey, String.valueOf(time));
        String parmDES = encode(randomKey, jsonParm);

        JSONObject jsonObject = new JSONObject();
        try {
            if (parmDES != null) {
                jsonObject.put("ciphertext", parmDES.replace("\n", ""));
            }
            if (encryptRSA != null) {
                jsonObject.put("key", encryptRSA.replace("\n", ""));
            }
            if (timeDES != null) {
                jsonObject.put("time", timeDES.replace("\n", ""));
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
        Map<String, String> resultMap = new HashMap<>(1);
        resultMap.put("ciphertext", jsonObject.toString());
        return resultMap;
    }

    /**
     * @return
     * @Object parm 对参数进行加密
     * @date 2019/10/17 新的加密方式
     */
    @SuppressLint({"NewApi", "LocalSuppress"})
    public static Map<String, String> encryptNewType(Object parm) {
        if (parm == null) {
            throw new RuntimeException("parm is null!");
        }
        Log.e("dj", "parm===" + parm);
        String jsonParm = objectToJson(parm);
        Log.e("dj", "jsonParm===" + jsonParm);
        String randomKey = getRandomString(8);
        //对公钥进行RSA非对称加密
        String encryptRSA = null;
        try {
            encryptRSA = encryptRSA(randomKey, PUBLIC_KEY);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //对时间和参数进行DES对称加密
        long time = System.currentTimeMillis();
        String timeDES = encode(randomKey, String.valueOf(time));
        String parmDES = encode(randomKey, jsonParm);

        Map<String, String> jsonObject = new HashMap<>();
        if (parmDES != null) {
            jsonObject.put("ciphertext", parmDES.replace("\n", ""));
        }
        if (encryptRSA != null) {
            jsonObject.put("key", encryptRSA.replace("\n", ""));
        }
        if (timeDES != null) {
            jsonObject.put("time", timeDES.replace("\n", ""));
        }

        return jsonObject;
    }

    /**
     * @return
     * @Object parm 对参数进行加密
     * @date 2019/11/4 新的加密方式
     */
    @SuppressLint({"NewApi", "LocalSuppress"})
    public static Map<String, String> encryptString(String parm) {
        if (parm == null) {
            throw new RuntimeException("parm is null!");
        }
        Log.e("dj", "parm===" + parm);
        String randomKey = getRandomString(8);
        //对公钥进行RSA非对称加密
        String encryptRSA = null;
        try {
            encryptRSA = encryptRSA(randomKey, PUBLIC_KEY);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //对时间和参数进行DES对称加密
        long time = System.currentTimeMillis();
        String timeDES = encode(randomKey, String.valueOf(time));
        String parmDES = encode(randomKey, parm);

        Map<String, String> jsonObject = new HashMap<>();
        if (parmDES != null) {
            jsonObject.put("ciphertext", parmDES.replace("\n", ""));
        }
        if (encryptRSA != null) {
            jsonObject.put("key", encryptRSA.replace("\n", ""));
        }
        if (timeDES != null) {
            jsonObject.put("time", timeDES.replace("\n", ""));
        }

        return jsonObject;
    }

    @SuppressLint({"NewApi", "LocalSuppress"})
    public static Map<String, String> encryptVerifyCode(Object parm) {
        if (parm == null) {
            throw new RuntimeException("parm is null!");
        }
        String jsonParm = objectToJson(parm);
        Log.e("dj", "parm===" + jsonParm);
        String randomKey = getRandomString(8);
        //对公钥进行RSA非对称加密
        String encryptRSA = null;
        try {
            encryptRSA = encryptRSA(randomKey, PUBLIC_KEY);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //对时间和参数进行DES对称加密
        long time = System.currentTimeMillis();
        String timeDES = encode(randomKey, String.valueOf(time));
        String parmDES = encode(randomKey, jsonParm);

        JSONObject jsonObject = new JSONObject();
        try {
            if (parmDES != null) {
                jsonObject.put("ciphertext", parmDES.replace("\n", ""));
            }
            if (encryptRSA != null) {
                jsonObject.put("key", encryptRSA.replace("\n", ""));
            }
            if (timeDES != null) {
                jsonObject.put("time", timeDES.replace("\n", ""));
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
        Map<String, String> resultMap = new HashMap<>(1);
        resultMap.put("note", jsonObject.toString());
        return resultMap;
    }

    /**
     * @param publicKey 公钥
     * @return
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    public static String encryptRSA(String randomKey, String publicKey) {
        byte[] bytes;
        try {
            bytes = randomKey.getBytes(CHARSET);
            String decodePublicKey = publicKey.replace("\r\n", "");
            RSAPublicKey rsaPublicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(android.util.Base64.decode(decodePublicKey.getBytes(), android.util.Base64.DEFAULT)));
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.PUBLIC_KEY, rsaPublicKey);
            bytes = cipher.doFinal(bytes);
            return android.util.Base64.encodeToString(bytes, android.util.Base64.DEFAULT);
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param length
     * @return 生成指定length的随机字符串（A-Z，a-z，0-9,+/）
     */
    public static String getRandomString(int length) {
        String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(str.length());
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }

    /**
     * 解密
     *
     * @param src      String
     * @param password String
     * @return String
     */
    @SuppressLint("NewApi")
    public static String decrypt(String src, String password) {
        try {
            // 初始化向量
            IvParameterSpec iv = new IvParameterSpec(password.getBytes());
            // 创建一个DESKeySpec对象
            DESKeySpec desKey = new DESKeySpec(password.getBytes());
            // 创建一个密匙工厂
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");// 返回实现指定转换的 Cipher 对象
            // 将DESKeySpec对象转换成SecretKey对象
            SecretKey securekey = keyFactory.generateSecret(desKey);
            // Cipher对象实际完成解密操作
            Cipher cipher = Cipher.getInstance("DES");
            // 用密匙初始化Cipher对象
            cipher.init(Cipher.DECRYPT_MODE, securekey, iv);
            // 真正开始解密操作
            return String.valueOf(cipher.doFinal(Base64.encode(src.getBytes(), Base64.DEFAULT)));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    //    private final static String TRANSFORMATION = "DES/CBC/PKCS5Padding";//DES是加密方式 CBC是工作模式 PKCS5Padding是填充模式
    private final static String TRANSFORMATION = "DES";//DES是加密方式 CBC是工作模式 PKCS5Padding是填充模式
    private final static String IVPARAMETERSPEC = "01020304";////初始化向量参数，AES 为16bytes. DES 为8bytes.
    private final static String ALGORITHM = "DES";//DES是加密方式
    private static final String SHA1PRNG = "SHA1PRNG";//// SHA1PRNG 强随机种子算法, 要区别4.2以上版本的调用方法

    // 对密钥进行处理
    private static Key getRawKey(String key) throws Exception {
        DESKeySpec dks = new DESKeySpec(key.getBytes(CHARSET));
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
        return keyFactory.generateSecret(dks);
    }

    /**
     * DES算法，加密
     *
     * @param data 待加密字符串
     * @param key  加密私钥，长度不能够小于8位
     * @return 加密后的字节数组，一般结合Base64编码使用
     */
    public static String encode(String key, String data) {
        return encode(key, data.getBytes());
    }


    /**
     * DES算法，加密
     *
     * @param data 待加密字符串
     * @param key  加密私钥，长度不能够小于8位
     * @return 加密后的字节数组，一般结合Base64编码使用
     */
    public static String encode(String key, byte[] data) {
        if (data == null) {
            throw new RuntimeException("data is null!");
        }
        try {
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            IvParameterSpec iv = new IvParameterSpec(IVPARAMETERSPEC.getBytes(CHARSET));
            cipher.init(Cipher.ENCRYPT_MODE, getRawKey(key), iv);
            byte[] bytes = cipher.doFinal(data);
            return android.util.Base64.encodeToString(bytes, android.util.Base64.DEFAULT);
        } catch (Exception e) {
            return null;
        }
    }


    /**
     * 获取编码后的值
     *
     * @param key
     * @param data
     * @return
     */
    public static String decode(String key, String data) {
        return decode(key, android.util.Base64.decode(data, android.util.Base64.DEFAULT));
    }

    /**
     * DES算法，解密
     *
     * @param data 待解密字符串
     * @param key  解密私钥，长度不能够小于8位
     * @return 解密后的字节数组
     */
    public static String decode(String key, byte[] data) {
        try {
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            IvParameterSpec iv = new IvParameterSpec(IVPARAMETERSPEC.getBytes(CHARSET));
            cipher.init(Cipher.DECRYPT_MODE, getRawKey(key), iv);
            byte[] original = cipher.doFinal(data);
            String originalString = new String(original);
            return originalString;
        } catch (Exception e) {
            return null;
        }
    }

}
